# model

# allow to chose a file which can be uploaded to the connected storage-services...

# SOME IMPORTANT INFORMATION:
# Documentation about howto upload keys into S3
# http://docs.amazonwebservices.com/AmazonS3/latest/index.html?HTTPPOSTForms.html
# http://doc.s3.amazonaws.com/proposals/post.html
# http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1434
# http://s3.amazonaws.com/doc/s3-example-code/post/post_sample.html

from google.appengine.ext import webapp

from controller.BuildStorageInfo import *

from Utilities import *
from model.octopus.datastore.OctopusCloudDatabaseRaidLevel import *
from model.octopus.raid.DeleteChoosenRaidLevel import DeleteChoosenRaidLevel


class SelectData(webapp.RequestHandler):
    def post(self):
        utilities = Utilities()
        
        # get the chosen raid-level
        raid = self.request.get('RAIDLevel')
        
        # check, if the chosen raid-level is raid-5. if yes, then initialize the local database with the storage-services
        if raid == utilities.getRaidFiveText():
            self.initStorageOrderDB(utilities)
        
        # call the get-method to continue with the routine..
        self.get(raid)
    
    def get(self, raid=None):
        utilities = Utilities()
        
        # get some basic data
        username = utilities.getUsername()
        userText = utilities.getUserText()
        
        # routine if user is logged-in or not
        if username:
            urlText = utilities.getUrlTextLogout()
            url = utilities.getLogout(self)
            
            # checks if any credentials for this user exist
            credentials = utilities.getCredentials(username)
            results = credentials.fetch(100)
            amount = credentials.count()
            
            # get the stored raid-level
            raidLevel = utilities.getRaidLevel(username)
            
            # get the stored info about the property 'storagesEmpty'
            storagesEmpty = utilities.getPropertyStoragesEmpty(username)
            
            # check if the storages are empty..            
            areEmpty = utilities.prepareToPersist(username, results)
            
            # check if there is already a raid-level chosen, if not (raidLevel = None) than persist the chosen one...
            if (raidLevel == None) or (raidLevel != None and areEmpty == True) or (raidLevel != None and areEmpty == False):
                
                # if there are three storage-services available and no raid-level is chosen, yet, than set the chosen one
                if amount == 3:
                    
                    # if storagesEmpty has already a valid value
                    if storagesEmpty != None:
                        
                        # if the attribute has chanced, than delete the old entry and persist the new one..
                        if storagesEmpty != areEmpty:
                            self.deleteRaidEntry(username)
                            self.persistRaidInfo(utilities, username, raidLevel, areEmpty)
                    
                    # delete the local raid-level-entry only, when a new one is chosen
                    # if the deletion is performed everytime, when the '/selectdata'-page is reloaded, there will be no info about the raid-level
                    if raid != None:
                        # delete first the old choice, before persist the new one
                        self.deleteRaidEntry(username)
                        
                        if areEmpty != None:
                            # persist the choice of the user                    
                            self.persistRaidInfo(utilities, username, raid, areEmpty)
                    
            if amount > 0:
                # responsible for the upload-data-routine
                self.manageDataUpload(utilities, credentials, username, userText, urlText, url, raid, raidLevel)
            else:
                self.redirect('/regions')
        else:
            self.redirect('/')

            
    # prepare data-upload-routine
    def manageDataUpload(self, utilities, credentials, username, userText, urlText, url, raid, raidLevel):
        # get the necessary regionnames from the utilities-class
        amazon = utilities.getAmazonText()
        google = utilities.getGoogleText()
        openStack = utilities.getOpenStackText()
        
        # create an empty-list, that will contain the available active-zones (certainly only this, to which the user is connected)
        activeZoneList = []
        
        # get the credentials
        results = credentials.fetch(100)
        
        # routine, if credentials are availible or not
        if results:
            # determine the available credentialType(s) for the credentials
            for result in results:
                credentialType = result.credentialType
                regionname = result.regionname
                
                # determine the available credentialType(s) and add them to a list
                if credentialType == amazon:
                    activeZoneList.append(credentialType)
                elif credentialType == google:
                    activeZoneList.append(credentialType)
                elif credentialType == openStack:
                    activeZoneList.append(credentialType)
                else:
                    self.redirect('/')
            
            # initialize storage-connections
            amazonStorageConnection = None
            googleStorageConnection = None
            openStackStorageConnection = None

            # connect with every available storage-service (active-zone)
            for currentZone in activeZoneList:
                # determine the active-zone
                if currentZone == amazon:
                    # connect with amazon-storage
                    amazonStorageConnection, regionname = utilities.getStorageServiceConnection(username, currentZone)
                elif currentZone == google:
                    # connect with google-storage
                    googleStorageConnection, regionname = utilities.getStorageServiceConnection(username, currentZone)
                elif currentZone == openStack:
                    # connect with openStack-storage
                    openStackStorageConnection, regionname = utilities.getStorageServiceConnection(username, currentZone)
                    
            # get bucketname
            bucketname = utilities.getBucketname(username)

            # initialize the keyLists - it's possible that the method 'getBucketKeyList' gets an exception - therefore the key-lists must have a default-value
            keyListAmazon = []
            keyListGoogle = []
            keyListOpenStack = []
            
            # get the bucket-key-list from amazon
            if amazonStorageConnection:
                keyListAmazon = utilities.getBucketKeyList(amazonStorageConnection, bucketname)
            
            # get the bucket-key-list from google
            if googleStorageConnection:
                keyListGoogle = utilities.getBucketKeyList(googleStorageConnection, bucketname)
            
            # get the bucket-key-list from openStack
            if openStackStorageConnection:
                keyListOpenStack = utilities.getBucketKeyList(openStackStorageConnection, bucketname)
                
            # get the number of entries
            credentialAmount = credentials.count()
            
            # get the raid-text
            raidOne = utilities.getRaidOneText()
            raidFive = utilities.getRaidFiveText()
            
            # check if there is more then one storage-service available
            if credentialAmount > 1:
                # initialize the checksum-lists
                amazonMD5ChecksumList = None
                googleMD5ChecksumList = None
                openStackMD5ChecksumList = None
                
                # get MD5 checksums for each available active-zone
                # new active-zones must be added here
                for activeZone in activeZoneList:
                    if activeZone == amazon:
                        amazonMD5ChecksumList = utilities.getMD5Checksums(username, activeZone, keyListAmazon)
                    elif activeZone == google:
                        googleMD5ChecksumList = utilities.getMD5Checksums(username, activeZone, keyListGoogle)
                    elif activeZone == openStack:
                        # original way to get the checksum-list
                        # DO NOT DELETE!
                        #openStackMD5ChecksumList = utilities.getMD5Checksums(username, activeZone, keyListOpenStack)
    
                        # workaround to get the md5-chechsums for openstack (from the local database)
#                        openStackMD5ChecksumList = utilities.getMD5ChecksumListForOpenStack()
                        openStackMD5ChecksumList = utilities.getMD5ChecksumListByAttributesForOpenStack(keyListOpenStack)
                
                # if raid-5 is chosen, than continue with the else-part, because no check of sync is necessary...
                if (raidLevel == raidOne and credentialAmount == 2) or (raidLevel == None and credentialAmount == 2) or (raidLevel == None and credentialAmount == 1) or (raidLevel == raidOne and credentialAmount == 1) or (raidLevel == raidFive and credentialAmount == 1) or (raidLevel == raidFive and credentialAmount == 2) or (raidLevel == raidOne and credentialAmount == 3):
                    # compare the MD5 checksums
                    # extend the parameter-field with other md5-checksum-lists, if you wish to compare more lists
                    isSync = utilities.compareChecksums(amazonMD5ChecksumList, googleMD5ChecksumList, openStackMD5ChecksumList)
                    
                    if isSync == 'true':
#                        hintText = _('The available storage-services are synchronously')
                        hintText = 'The available storage-services are synchronously'
                        hintColor = 'green'
                        
                        # NOTE: 
                        #    for the presentation in the gui we have to choose one key-list as prior 1 to list the keys based on it's entries (default: keyListAmazon)
                        #    this may cause an error if we are not connected to amazon-s3. therefore we must make a selection
                        keyList = keyListAmazon
                        if keyListAmazon == None or keyListAmazon == []:
                            keyList = keyListGoogle
                            if keyListGoogle == None or keyListGoogle == []:
                                keyList = keyListOpenStack
                                if keyListOpenStack == None or keyListOpenStack == []:
                                    keyList = []
                        
                        self.callBuilder(userText, username, url, urlText, hintText, hintColor, keyList, isSync)
                    elif isSync == 'false':
#                        hintText = _('The available storage-services are not synchronously. If you wish to synchronize the storages, than click the button below the table.')
                        hintText = 'The available storage-services are not synchronously. If you wish to synchronize the storages, than click the button below the table.'
                        hintColor = 'red'
                        
                        # NOTE: 
                        #    for the presentation in the gui we have to choose one key-list as prior 1 to list the keys based on it's entries (default: keyListAmazon)
                        #    this may cause an error if we are not connected to amazon-s3. therefore we must make a selection
                        keyList = keyListAmazon
                        if keyListAmazon == None or keyListAmazon == []:
                            keyList = keyListGoogle
                            if keyListGoogle == None or keyListGoogle == []:
                                keyList = keyListOpenStack
                                if keyListOpenStack == None or keyListOpenStack == []:
                                    keyList = []
                        
                        self.callBuilder(userText, username, url, urlText, hintText, hintColor, keyList, isSync)
                else:
                    # continue here, when raid-level-5 is chosen.
                    hintText = ''
                    hintColor = ''
                    
                    keyList = keyListAmazon
                    if keyListAmazon == None or keyListAmazon == []:
                        keyList = keyListGoogle
                        if keyListGoogle == None or keyListGoogle == []:
                            keyList = keyListOpenStack
                            if keyListOpenStack == None or keyListOpenStack == []:
                                keyList = []
                    
                    self.callBuilder(userText, username, url, urlText, hintText, hintColor, keyList)
                                   
            elif credentialAmount == 1:
#                hintText = _('You are connected to only one storage-service - no redundancy possible')
                hintText = 'You are connected to only one storage-service - no redundancy possible'
                hintColor = 'black'
                
                # NOTE: 
                #    for the presentation in the gui we have to choose one key-list as prior 1 to list the keys based on it's entries (default: keyListAmazon)
                #    this may cause an error if we are not connected to amazon-s3. therefore we must make a selection
                keyList = keyListAmazon
                if keyListAmazon == None or keyListAmazon == []:
                    keyList = keyListGoogle
                    if keyListGoogle == None or keyListGoogle == []:
                        keyList = keyListOpenStack
                        if keyListOpenStack == None or keyListOpenStack == []:
                            keyList = []
                
                # when the user has entered credentials for only one storage-service there is no sync...
                self.callBuilder(userText, username, url, urlText, hintText, hintColor, keyList)

            elif credentialAmount == 0:
                # if no credentials available, then redirect to the main-page  
                self.redirect('/')
    
    # initialize the storage-order-database (call the method from utilities-class)
    # this method should be called, only when a new raid-level is chosen and it is raid-5
    def initStorageOrderDB(self, utilities):
        username = utilities.getUsername()
        utilities.initStorageOrderDatabase(username)
    
    # prepare to persist the chosen raid-level, therefore some information are needed
    def prepareToPersist(self, utilities, username, results, raid):
        areEmpty = utilities.prepareToPersist(username, results, raid)
        
        # persist the information
        self.persistRaidInfo(utilities, username, raid, areEmpty)

    # persist some necessary information about the chosen raid-configuration
    def persistRaidInfo(self, utilities, username, raid, areEmpty):
        utilities.persistRaidInfo(username, raid, areEmpty)

    # delete the persist raid-entry with the raid-level
    def deleteRaidEntry(self, username):
        deleteRaidEntry = DeleteChoosenRaidLevel()
        deleteRaidEntry.get()
    
    # this text is used multiple times in this class - so it was extracted in a separate method    
    def getHintTextCouldNotConnect(self):
#        hintText = _("Couldn't connect - an error occurred")
        hintText = "Couldn't connect - an error occurred"
        return hintText
    
    # this text is used multiple times in this class - so it was extracted in a separate method    
    def getHintTextNoKeys(self):
#        hintText = _('There are no keys inside the storage-services')
        hintText = 'There are no keys inside the storage-services'
        return hintText
    
    # this text is used multiple times in this class
    def getHintTextOnlyOneStorage(self):
#        hintText = _('You are connected to only one storage-service - no redundancy possible')
        hintText = 'You are connected to only one storage-service - no redundancy possible'
        return hintText
    
    # responsible for the call of the get-method of the BuildStorageInfo-Class
    def callBuilder(self, userText, username, url, urlText, hintText, hintColor, keyList, isSync=''):
        templateValues = {
                          'userText': userText,
                          'user': username,
                          'urlText': urlText,
                          'url': url,
                          'urlText': urlText,
                          'hintText': hintText,
                          'hintColor': hintColor
                          }
        
        builder = BuildStorageInfo()
        builder.get(self, templateValues, keyList, isSync)
        
    
        